package com.nageoffer.jobtrain.admin.service.chain;

import org.springframework.beans.BeansException;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * author：唐晨
 * Oj题目上下文容器
 */
@Component
public final class OjQuestionChainContext<T> implements ApplicationContextAware, CommandLineRunner {
    /**
     * 获取到spring应用上下文，通过SpringIoc获取应用Bean
     */
    private ApplicationContext applicationContext;

    /**
     * 责任链实现类存储器
     * Key：{@link OjQuestionAbstractChainHandler#mark()} 责任链组件标识
     * Val：{@link OjQuestionAbstractChainHandler} 一组责任链实现 Spring Bean 集合
     */
    private final Map<String, List<OjQuestionAbstractChainHandler>> abstractChainHandlerContainer = new HashMap<>();

    /**
     * 责任链组件执行
     *
     * @param mark         责任链组件标识
     * @param requestParam 请求参数
     */
    public void handler(String mark, T requestParam) {
        // 根据不同责任链标识 mark 取出对应的一组责任链集合
        List<OjQuestionAbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.get(mark);
        if (CollectionUtils.isEmpty(abstractChainHandlers)) {
            throw new RuntimeException(String.format("[%s] 责任链 ID 未定义.", mark));
        }
        // 依次执行mark标志中的一组责任链集合
        abstractChainHandlers.forEach(each -> {
            each.handler(requestParam);
        });
    }

    @Override
    public void run(String... args) throws Exception {
        // 从 Spring Ioc容器中获取指定接口 Spring Bean集合
        Map<String, OjQuestionAbstractChainHandler> chainFilterMap = applicationContext.getBeansOfType(OjQuestionAbstractChainHandler.class);
        chainFilterMap.forEach((beanName, bean) -> {
            // 判断Mark是否已经存在抽象责任链容器中，如果已经存在，直接向集合中添加；如果不存在，创建 Mark和对应的集合 - 这里是某个责任链的接口bean集合
            List<OjQuestionAbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.getOrDefault(bean.mark(), new ArrayList<>());
            abstractChainHandlers.add(bean);
            abstractChainHandlerContainer.put(bean.mark(), abstractChainHandlers);
        });
        // 再对每个Mark 里面的责任链对应的责任链实现类集合进行一个优先级排序（优先级小的排在前面）
        abstractChainHandlerContainer.forEach((mark, unsortedChainHandlers) -> {
            unsortedChainHandlers.sort(Comparator.comparing(Ordered::getOrder));
        });
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
